package ro.myApp.esb.exceptions;

import java.util.Iterator;
import java.util.List;

import javax.mail.AuthenticationFailedException;

import org.mule.DefaultExceptionStrategy;
import org.mule.DefaultMuleEvent;
import org.mule.DefaultMuleMessage;
import org.mule.DefaultMuleSession;
import org.mule.MuleSessionHandler;
import org.mule.RequestContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleEventContext;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.endpoint.EndpointURI;
import org.mule.api.endpoint.ImmutableEndpoint;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.message.ExceptionMessage;
import org.mule.retry.RetryPolicyExhaustedException;
import org.mule.util.CollectionUtils;

public class MailerExceptionStrategy extends DefaultExceptionStrategy {

	@Override
	protected void routeException(MuleMessage message, ImmutableEndpoint endpoint, Throwable err) {
		List<?> endpoints = getEndpoints(err);
		if (CollectionUtils.isNotEmpty(endpoints)) {
			try {
				logger.error("Message being processed is: " + (message == null ? "null" : message.toString()));
				MuleEventContext ctx = RequestContext.getEventContext();
				String component = "Unknown";
				EndpointURI endpointUri = null;
				if (ctx != null) {
					if (ctx.getService() != null) {
						component = ctx.getService().getName();
					}
					endpointUri = ctx.getEndpointURI();
				} else if (endpoint != null) {
					endpointUri = endpoint.getEndpointURI();
				}
				ExceptionMessage msg = new ExceptionMessage(getErrorMessagePayload(message), err, component, endpointUri);

				MuleMessage exceptionMessage;
				if (ctx == null) {
					exceptionMessage = new DefaultMuleMessage(msg);
				} else {
					exceptionMessage = new DefaultMuleMessage(msg, ctx.getMessage());
				}
				
				//this is the place where transaction will be rolled back if fail to send email 
				if((msg.getException() instanceof javax.mail.MessagingException ||
						msg.getException() instanceof RetryPolicyExhaustedException || 
							msg.getException() instanceof AuthenticationFailedException)){
					throw new RuntimeException(msg.getException());
				}
				
				for (Iterator<?> itr = endpoints.iterator(); itr.hasNext();) {
					OutboundEndpoint ep = (OutboundEndpoint) itr.next();
					DefaultMuleSession muleSession = new DefaultMuleSession(exceptionMessage, new MuleSessionHandler(), muleContext);
					MuleEvent exceptionEvent = new DefaultMuleEvent(exceptionMessage, ep, muleSession, true);
					exceptionEvent = RequestContext.setEvent(exceptionEvent);
					ep.send(exceptionEvent);

					if (logger.isDebugEnabled()) {
						logger.debug("Routed Exception message via " + ep);
					}
				}
			} catch (MuleException e) {
				logFatal(message, e);
				closeStream(message);
			}
		} else {
			handleTransaction(err);
			closeStream(message);
		}
	}
	
	@Override
	protected void logException(Throwable t) {
		super.logException(t);
		logger.error("Email error:", t);
	}
}
